/********************************************************************************************/
/*																							*/
/*							Twn_ObjectMver.cpp												*/
/*																							*/
/*	Description: library contains a function that manages the runtime object movements		*/
/*				 between cells and mast.													*/
/*																							*/
/*	Date:		 20/01/2003																	*/
/*																							*/
/*	Author:		 M.Tavella																	*/
/*																							*/
/********************************************************************************************/

#define ALONE_TWN_OBJMOVER

#include "Twn_ObjectMover.h"
	
#define OPMODE_TIME				4000
#define MM_ROT_CL				45
#define MM_ROT_OP				0

#define MIN_CYCLE_TIME			500
#define DEF_CYCLE_TIME			2000

#define MIN_CYCLE_REFR			2
#define DEF_CYCLE_REFR			4

#define DEF_CLUSTER_MOV_TOLL	10.0
#define DEF_CLUSTER_MOV_CHECK	70.0
#define CLGR_WEIGHT_DIFF		5.0

#define OBM_LOG_INF				0
#define OBM_LOG_WRN				1
#define OBM_LOG_ERR				2

#define CLGR_MSG_NO_ENG			1
#define CLGR_MSG_NO_REL			2

#define LOG_MSG_LEN				512

#define SLEEP_AFTER_START		2000
#define SLEEP_AFTER_STOP		1000

DWORD	cycleTime;
DWORD	graphRefreshCycle;
float	clusterMoveTollerance;
float	clusterMoveCheck;
TCHAR	OBM_logMsg[LOG_MSG_LEN];
TCHAR	OBM_logPath[MAX_PATH];
BOOL	OBM_LogActive;



BOOL WINAPI DllMain(HINSTANCE hinstDLL,  // handle to DLL module
					DWORD fdwReason,     // reason for calling function
					LPVOID lpReserved )  // reserved
					{
	LONG	res;
	LPDWORD	type;
	LPBYTE	data;
	LPDWORD size;
	HKEY	hKey;
	TCHAR	szProductType[ENM_NAME_L];
    DWORD	dwBufLen = ENM_NAME_L;
	DWORD	active;
    
	size = 0;
	data = 0;
	type = 0;
	
	switch(fdwReason){ 
		case DLL_PROCESS_ATTACH:
			res = RegOpenKeyEx(	HKEY_LOCAL_MACHINE, 
							TEXT("SOFTWARE\\ABB\\Power Generation Portal\\Tianwan\\Twn_ObjectMover"),
							0,
							KEY_QUERY_VALUE,
							&hKey);
			if(res != ERROR_SUCCESS)
				return(FALSE);	
			
			res = RegQueryValueEx(	hKey,
									TEXT("LogPath"),
									NULL,
									NULL,
									(LPBYTE)szProductType,
									&dwBufLen);
			if(res == ERROR_SUCCESS)
				_stprintf_s(OBM_logPath, (TCHAR*)szProductType);
			
			active = 0;
			dwBufLen = sizeof(active);
			res = RegQueryValueEx(	hKey,
									TEXT("LogActive"),
									NULL,
									NULL,
									(LPBYTE)&active,
									&dwBufLen);
			if(res == ERROR_SUCCESS){
				if((DWORD)active == 0)
					OBM_LogActive = false;
				else
					OBM_LogActive = true;
			}
			
			active = 0;
			dwBufLen = sizeof(active);
			res = RegQueryValueEx(	hKey,
									TEXT("CycleTime"),
									NULL,
									NULL,
									(LPBYTE)&active,
									&dwBufLen);
			if(res == ERROR_SUCCESS){
				if(active < MIN_CYCLE_TIME)
					cycleTime = MIN_CYCLE_TIME;
				else
					cycleTime = active;
			}else
				cycleTime = DEF_CYCLE_TIME;

			active = 0;
			dwBufLen = sizeof(active);
			res = RegQueryValueEx(	hKey,
									TEXT("GraphRefreshCycle"),
									NULL,
									NULL,
									(LPBYTE)&active,
									&dwBufLen);
			if(res == ERROR_SUCCESS){
				if(active < MIN_CYCLE_REFR)
					graphRefreshCycle = MIN_CYCLE_REFR;
				else
					graphRefreshCycle = active;
			}else
				graphRefreshCycle = DEF_CYCLE_REFR;

			active = 0;
			dwBufLen = sizeof(active);
			res = RegQueryValueEx(	hKey,
									TEXT("ClusterMoveTollerance"),
									NULL,
									NULL,
									(LPBYTE)&active,
									&dwBufLen);
			if(res == ERROR_SUCCESS){
				if(active <= 0)
					clusterMoveTollerance = (float)(DEF_CLUSTER_MOV_TOLL);
				else
					clusterMoveTollerance = (float)(active);
			}else
				clusterMoveTollerance = (float)(DEF_CLUSTER_MOV_TOLL);
			
			active = 0;
			dwBufLen = sizeof(active);
			res = RegQueryValueEx(	hKey,
									TEXT("ClusterCheckQuote"),
									NULL,
									NULL,
									(LPBYTE)&active,
									&dwBufLen);
			if(res == ERROR_SUCCESS){
				if(active <= 0)
					clusterMoveCheck = (float)(DEF_CLUSTER_MOV_CHECK);
				else
					clusterMoveCheck = (float)(active);
			}else
				clusterMoveCheck = (float)(DEF_CLUSTER_MOV_CHECK);
			break;
		default:
			break;
	}
    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}

/********************************************************************************************/
/*																							*/
/*	Function:		ObjectMover																*/
/*																							*/
/*	Description:	Activate the automatic objects movement process							*/
/*																							*/
/*	Input:			hWnd		-	Handle of the calling window							*/
/*																							*/
/*	Return:			retSt		-	RT_NORMAL	for success									*/
/*								-	RT_FAILED	otherwise									*/
/*																							*/
/********************************************************************************************/
RETSTAT ObjectMover(HWND hWnd){
	RETCOND			retCnd;
	RETSTAT			retSt;
	HWND			manHwnd;
	TAGIDX			tiStart;
	TAGIDX			tiLastOPOK;
	TAGIDX			tiLastOPNOOK;
	TAGIDX			tiMMMReq;
	TAGIDX			tiMMFixMReq;
	TAGIDX			tiMMClusMReq;
	TAGIDX			tiMMRotMReq;
	TAGIDX			tiMMFixOp;
	TAGIDX			tiMMFixCl;
	TAGIDX			tiMMAngle;
	TAGIDX			tiMMClusPos;
	TAGIDX			tiMMClusSP;
	TAGIDX			tiMMPos;
	TAGIDX			tiMMSp;
	TAGIDX			tiFaIdx;
	TAGIDX			tiCljIdx;
	TAGIDX			tiHecaIdx;
	TAGIDX			tiCovIdx;
	TAGIDX			tiFfdsIdx;
	TAGIDX			tiClfIdx;
	TAGIDX			tiClIdx;
	TAGIDX			tiFALVLDown;
	TAGIDX			tiFALVLLevel;
	TAGIDX			tiClOverload;
	TAGIDX			tiClNotEngaged;
	TAGVALEX		tagVal;
	GENIDX			contIdx;
	ZONENAME		zoneName;
	ZONENAME		supZoneName;
	GENIDX			zoneIdx;
	OBJTMM			objtMM;
	OBJTMM			oldObjtMM;
//	OBJTMM			dummy;
	OBJTCELL		objtCell;
	t_cell			cell;
	t_falv			falvlData;
	t_camp			camp;
	TCHAR			opMsg[512];
	int				vx;
	int				vy;
//	int				i;
	int				opMode;
	int				station;
	int				flag;
	int				inSim;
	int				refreshCount;
	int				opCount;
	float			px;
	float			py;
	float			mmAngle;
	float			clusStart;
//	float			mmPos;
//	float			mmSp;
	float			clusTDZ1_LOAD;
	float			clusTDZ1_TK13;
	float			clusTDZ21;
	float			clusTDZ23;
	float			clusTDZ3;
	float			mmTDPos;
	float			clgrPos;
	float			tdPos;
	bool			mmClus;
	bool			mmFix;
	bool			mmRot;
	bool			mmMov;
	bool			falvl;
	bool			start;
	bool			temp;
	bool			ok;
	bool			nook;
	bool			fixOp;
	bool			fixCl;
	bool			mastUpdated;
	bool			cellUpdated;
	bool			sendMsg;
	bool			clusTD;
	bool			first;
	bool			passive;
	bool			refresh;
	bool			movInProg;
	bool			lastStart;
	TAGIDX			wTagIdx;
	TAGVALEX		wTagVal;
	float			tresholdWeight;

	if(hWnd != NULL)
		sendMsg = true;
	else
		sendMsg = false;


	retSt = GetInfiBlockVal(8291, 0, &tresholdWeight);
	if(retSt != RT_NORMAL)
		return(RT_FAILED);

	//Cluster Gripper Load Cell//
	retCnd = GetTagIdx(TWN_MM_CLGR_LOAD, &wTagIdx);
	if(retCnd != R_NORMAL){
		MessageBox(hWnd, _T("Cannot retrieve tag 9BP1_STRAIN identifier."),_T("Error"), MB_OK | MB_ICONERROR);
		return(RT_FAILED);
	}


	retCnd = GetTagIdx(TWN_START_MOV, &tiStart);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);
	
	retCnd = GetTagIdx(TWN_LAST_OP_OK, &tiLastOPOK);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_LAST_OP_NOOK, &tiLastOPNOOK);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_FAGRL_MREQ, &tiMMFixMReq);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_CLGR_MREQ, &tiMMClusMReq);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_MM_ROT_MREQ, &tiMMRotMReq);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_FAGRL_FIXED, &tiMMFixCl);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_FAGRL_UNFIXED, &tiMMFixOp);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_MM_ROT_POS, &tiMMAngle);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_CLGR_POS, &tiMMClusPos);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_FA_MOVE, &tiFaIdx);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_CLUSCAS_MOVE, &tiCljIdx);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_HECA_MOVE, &tiHecaIdx);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_HECA_PLUG_MOVE, &tiCovIdx);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_FFDS_PLUG_MOVE, &tiFfdsIdx);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_CLUSFRM_MOVE, &tiClfIdx);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_CLUS_MOVE, &tiClIdx);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_FAGR_POS, &tiMMPos);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_FAGR_SP, &tiMMSp);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_FAGR_MREQ, &tiMMMReq);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_FALVL_DOWN_REQ, &tiFALVLDown);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_FALV_POS, &tiFALVLLevel);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_TRIP_MM_CL_OL, &tiClOverload);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_TRIP_MM_CL_NOT_EN, &tiClNotEngaged);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_CLGR_SP, &tiMMClusSP);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retSt = GetInfiBlockVal(3483, 0, &clusTDZ21);
	if(retSt != RT_NORMAL)
		return(RT_FAILED);

	retSt = GetInfiBlockVal(8722, 0, &clusTDZ23);
	if(retSt != RT_NORMAL)
		return(RT_FAILED);

	retSt = GetInfiBlockVal(3484, 0, &clusTDZ3);
	if(retSt != RT_NORMAL)
		return(RT_FAILED);

	retSt = GetInfiBlockVal(8618, 0, &clusTDZ1_LOAD);
	if(retSt != RT_NORMAL)
		return(RT_FAILED);

	retSt = GetInfiBlockVal(8720, 0, &clusTDZ1_TK13);
	if(retSt != RT_NORMAL)
		return(RT_FAILED);

	retSt = GetMastSituation(&oldObjtMM);
	if(retSt != RT_NORMAL)
		return(retSt);

	mmClus = false;
	mmFix = false;
	mmRot = false;
	mmMov = false;
	start = false;
	lastStart = false;
	temp = false;
	cellUpdated = false;
	mastUpdated = false;
	manHwnd = NULL;
	first = true;
	movInProg = false;
	opCount = 0;

	GetStationID(&station);

	if(OBM_LogActive){
		_stprintf_s(OBM_logMsg, _T("ObjectMover finished loading parameters and is starting cycle."));
		OBM_LogFileWrite(OBM_LOG_INF, OBM_logMsg, 0);
	}

	if(OBM_LogActive){
		_stprintf_s(OBM_logMsg, _T("Object mover station is %d."), station);
		OBM_LogFileWrite(OBM_LOG_INF, OBM_logMsg, 0);
	}

	refreshCount = 0;

	while(1){
		manHwnd = FindWindow(NULL, _T("Manual Mode Management"));
		
		retSt = GetDynCurrentMode(&opMode);
		if(retSt != RT_NORMAL){
			if(OBM_LogActive){
				_stprintf_s(OBM_logMsg, _T("Cannot retrieve current operating mode. Goto sleep."));
				OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 1);
			}
			goto SLEEP;
		}

		retSt = GetMastSituation(&objtMM);
		if(retSt != RT_NORMAL){
			if(OBM_LogActive){
				_stprintf_s(OBM_logMsg, _T("Cannot retrieve current mast situation. Goto sleep."));
				OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 2);
			}
			goto SLEEP;
		}

		if((opMode == M_AUTOMATIC) || (opMode == M_SEMIAUTO)){
			if(station == STATION_1){
				sysInSimulation(&inSim);
				if(inSim != 0){
					passive = false;
				}else{
					GetStationTCFlag(STATION_2, &flag);
					if(flag == CTRL_TC)
						passive = true;
					else
						passive = false;
				}
			}
			else{
				GetStationTCFlag(STATION_1, &flag);
				if(flag == CTRL_TC)
					passive = true;
				else
					passive = false;
			}
		}else{
			if(station == STATION_1){
				sysInSimulation(&inSim);
				if(inSim != 0){
					passive = false;
				}else{
					GetStationTCFlag(STATION_1, &flag);
					if(flag == CTRL_MAN_SLAVE)
						passive = true;
					else
						passive = false;
				}
			}
			else{
				GetStationTCFlag(STATION_2, &flag);
				if(flag == CTRL_MAN_SLAVE)
					passive = true;
				else
					passive = false;
			}
		}

		if(!passive){
			retCnd = SetObjectOnMast(MAIN_MAST, objtMM);
			if(retCnd != R_NORMAL)
				goto SLEEP;

			retSt = SetWeightOnMast(objtMM);

			retSt = SetToMove(objtMM);
		}

		memcpy(&oldObjtMM, &objtMM, sizeof(OBJTMM));

		retSt = boolTag(tiStart, &start);
		if(retSt != RT_NORMAL)
			goto SLEEP;
		
		if(start && !movInProg){
			movInProg = true;

			Sleep(SLEEP_AFTER_START);

			//New movement started//		
			if(OBM_LogActive){
				opCount++;
				_stprintf_s(OBM_logMsg, _T("Movement %d started."), opCount);
				OBM_LogFileWrite(OBM_LOG_INF, OBM_logMsg, 2);
			}
			retSt = boolTag(tiMMFixMReq, &mmFix);
			if(retSt != RT_NORMAL){
				if(OBM_LogActive){
					_stprintf_s(OBM_logMsg, _T("Error checking latch movemt request tag."));
					OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 30);
				}
				goto SLEEP;
			}
			retSt = boolTag(tiMMClusMReq, &mmClus);
			if(retSt != RT_NORMAL){
				if(OBM_LogActive){
					_stprintf_s(OBM_logMsg, _T("Error checking cluster movemt request tag."));
					OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 30);
				}
				goto SLEEP;
			}
			if(mmClus){
				retCnd = TagRead(&tiMMClusPos, &tagVal);
				if(retCnd != R_NORMAL){
					goto SLEEP;
				}
				clusStart = tagVal.value.val_float;
			}
			retSt = boolTag(tiMMRotMReq, &mmRot);
			if(retSt != RT_NORMAL){
				goto SLEEP;
			}
			retSt = boolTag(tiMMMReq, &mmMov);
			if(retSt != RT_NORMAL){
				goto SLEEP;
			}

			retSt = boolTag(tiFALVLDown, &falvl);
			if(retSt != RT_NORMAL){
				goto SLEEP;
			}
		}else if(!start && movInProg){
			movInProg = false;
			//Movement ended//
			cellUpdated = false;
			mastUpdated = false;
			if(mmRot || mmFix || mmClus){
				Sleep(SLEEP_AFTER_STOP);
				retSt = boolTag(tiLastOPOK, &ok);
				if(retSt != RT_NORMAL){
					goto SLEEP;
				}
				retSt = boolTag(tiLastOPNOOK, &nook);
				if(retSt != RT_NORMAL){
					goto SLEEP;
				}
				if(ok && !nook){
					if(OBM_LogActive){
						_stprintf_s(OBM_logMsg, _T("Movement %d ended successfully."), opCount);
						OBM_LogFileWrite(OBM_LOG_INF, OBM_logMsg, 2);
					}
					//Movement successfull//
					retSt = GetMastPosInfiSC(MAIN_MAST, &px, &py, &zoneIdx);
					if(retSt != RT_NORMAL){
						if(OBM_LogActive){
							_stprintf_s(OBM_logMsg, _T("Error getting mast position from Infi."));
							OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 40);
						}
						goto SLEEP;
					}
					retSt = GetZonePhisVirtCoord(px, py, &vx, &vy);
					if(retSt != RT_NORMAL){
						if(OBM_LogActive){
							_stprintf_s(OBM_logMsg, _T("Error getting cell virtual coordinates."));
							OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 41);
						}
						goto SLEEP;
					}
					retSt = GetCellVirtCoo(vx, vy, &cell);
					if(retSt != RT_NORMAL){
						if(OBM_LogActive){
							_stprintf_s(OBM_logMsg, _T("Error getting cell info."));
							OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 42);
						}
						goto SLEEP;
					}
					memcpy(&objtCell, &cell.objt_cell, sizeof(OBJTCELL));
					retSt = GetMastSituation(&objtMM);
					if(retSt != RT_NORMAL){
						if(OBM_LogActive){
							_stprintf_s(OBM_logMsg, _T("Error getting mast situation."));
							OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 43);
						}
						goto SLEEP;
					}
					//Se il mast non e' in touchdown, non rilascio niente//
					retSt = MastInTouchdown(MAIN_MAST, &mmTDPos);
					if((retSt != RT_NORMAL) || (mmTDPos == -1)){
						if(OBM_LogActive){
							_stprintf_s(OBM_logMsg, _T("Mast is not in touchdown position!"));
							OBM_LogFileWrite(OBM_LOG_WRN, OBM_logMsg, 2);
						}
						goto SLEEP;
					}
					if(mmFix){
						retSt = boolTag(tiMMFixOp, &fixOp);
						if(retSt != RT_NORMAL){
							goto SLEEP;
						}
						retSt = boolTag(tiMMFixCl, &fixCl);
						if(retSt != RT_NORMAL){
							goto SLEEP;
						}
						if(OBM_LogActive){
							_stprintf_s(OBM_logMsg, _T("Movement is latch."));
							OBM_LogFileWrite(OBM_LOG_INF, OBM_logMsg, 2);
						}
						if(fixCl && !fixOp){
							//Il latch � chiuso//
							if(OBM_LogActive){
								_stprintf_s(OBM_logMsg, _T("Latch has been closed."));
								OBM_LogFileWrite(OBM_LOG_INF, OBM_logMsg, 2);
							}
							if((objtCell.obj[OBJT_N_HECA] != 0) && (objtCell.obj[OBJT_N_COVER] != 0)){
								retSt = RemoveObject(&objtCell, &objtMM, objtCell.o_id[OBJT_N_HECA], objtCell.obj[OBJT_N_HECA]);
								if(retSt != RT_NORMAL){
									goto SLEEP;
								}
							}
							else if((objtCell.obj[OBJT_N_FA] != 0) && (objtCell.obj[OBJT_N_COVER] == 0) && (objtCell.obj[OBJT_N_FFDS_COV] == 0)){
								retSt = RemoveObject(&objtCell, &objtMM, objtCell.o_id[OBJT_N_FA], objtCell.obj[OBJT_N_FA]);
								if(retSt != RT_NORMAL){
									goto SLEEP;
								}
							}
							else if((objtCell.obj[OBJT_N_CLUS_CAS] != 0) && (objtCell.obj[OBJT_N_FFDS_COV] == 0) && (objtCell.obj[OBJT_N_COVER] == 0)){
								retSt = RemoveObject(&objtCell, &objtMM, 0, objtCell.obj[OBJT_N_CLUS_CAS]);
								if(retSt != RT_NORMAL){
									goto SLEEP;
								}
							}
							else if(objtCell.obj[OBJT_N_COVER] != 0){
								retSt = RemoveObject(&objtCell, &objtMM, objtCell.o_id[OBJT_N_COVER], objtCell.obj[OBJT_N_COVER]);
								if(retSt != RT_NORMAL){
									goto SLEEP;
								}
							}
							else if(objtCell.obj[OBJT_N_FFDS_COV] != 0){
								retSt = RemoveObject(&objtCell, &objtMM, 0, objtCell.obj[OBJT_N_FFDS_COV]);
								if(retSt != RT_NORMAL){
									goto SLEEP;
								}
							}
							else if(objtCell.obj[OBJT_N_CLUS_FRM] != 0){
								retSt = RemoveObject(&objtCell, &objtMM, objtCell.o_id[OBJT_N_CLUS_FRM], objtCell.obj[OBJT_N_CLUS_FRM]);
								if(retSt != RT_NORMAL){
									goto SLEEP;
								}
							}
							retSt = UpdateCellSituation(vx, vy, &objtCell);
							if(retSt != RT_NORMAL){
								if(OBM_LogActive){
									_stprintf_s(OBM_logMsg, _T("Error updating cell (%d,%d) situation."), vx, vy);
									OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 3);
								}
								goto SLEEP;
							}
							cellUpdated = true;
							retSt = UpdateMastSituation(&objtMM);
							if(retSt != RT_NORMAL){
								if(OBM_LogActive){
									_stprintf_s(OBM_logMsg, _T("Error updating mast situation."), vx, vy);
									OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 4);
								}
								goto SLEEP;
							}
							mastUpdated = true;
						}else if(fixOp && !fixCl){
							//Il latch � aperto//
							if(OBM_LogActive){
								_stprintf_s(OBM_logMsg, _T("Latch has been opened."));
								OBM_LogFileWrite(OBM_LOG_INF, OBM_logMsg, 2);
							}
							//Controllo sul mast quale oggetto sto lasciando.//
							if(objtMM.obj[OBJT_N_HECA] != 0){
								retSt = InsertObject(&objtCell, &objtMM, objtMM.o_id[OBJT_N_HECA], objtMM.obj[OBJT_N_HECA], cell.type);
								if(retSt != RT_NORMAL){
									if(sendMsg)
										SendMessage(hWnd, WM_OP_FAILED, NULL, NULL);
									goto SLEEP;
								}
							}
							else if(objtMM.obj[OBJT_N_FA] != 0){
								retSt = InsertObject(&objtCell, &objtMM, objtMM.o_id[OBJT_N_FA], objtMM.obj[OBJT_N_FA], cell.type);
								if(retSt != RT_NORMAL){
									if(sendMsg)
										SendMessage(hWnd, WM_OP_FAILED, NULL, NULL);
									goto SLEEP;
								}
							}
							else if(objtMM.obj[OBJT_N_CLUS_CAS] != 0){
								retSt = InsertObject(&objtCell, &objtMM, 0, objtMM.obj[OBJT_N_CLUS_CAS], cell.type);
								if(retSt != RT_NORMAL){
									if(sendMsg)
										SendMessage(hWnd, WM_OP_FAILED, NULL, NULL);
									goto SLEEP;
								}
							}
							else if(objtMM.obj[OBJT_N_CLUS_FRM] != 0){
								retSt = InsertObject(&objtCell, &objtMM, objtMM.o_id[OBJT_N_CLUS_FRM], objtMM.obj[OBJT_N_CLUS_FRM], cell.type);
								if(retSt != RT_NORMAL){
									if(sendMsg)
										SendMessage(hWnd, WM_OP_FAILED, NULL, NULL);
									goto SLEEP;
								}
							}
							else if(objtMM.obj[OBJT_N_COVER] != 0){
								retSt = GetMastAngle(&mmAngle);
								if((mmAngle >= (float)(0 - TOLL_MM_GR)) && (mmAngle <= (float)(0 + TOLL_MM_GR))){
									retSt = InsertObject(&objtCell, &objtMM, objtMM.o_id[OBJT_N_COVER], objtMM.obj[OBJT_N_COVER], cell.type);
									if(retSt != RT_NORMAL){
										if(sendMsg)
											SendMessage(hWnd, WM_OP_FAILED, NULL, NULL);
										goto SLEEP;
									}
								}
							}
							else if(objtMM.obj[OBJT_N_FFDS_COV] != 0){
								retSt = GetMastAngle(&mmAngle);
								if((mmAngle >= (float)(0 - TOLL_MM_GR)) && (mmAngle <= (float)(0 + TOLL_MM_GR))){
									retSt = InsertObject(&objtCell, &objtMM, 0, objtMM.obj[OBJT_N_FFDS_COV], cell.type);
									if(retSt != RT_NORMAL){
										if(sendMsg)
											SendMessage(hWnd, WM_OP_FAILED, NULL, NULL);
										goto SLEEP;
									}
								}
							}
				
							retSt = UpdateCellSituation(cell.Virt_X, cell.Virt_Y, &objtCell);
							if(retSt != RT_NORMAL){
								if(sendMsg)
									SendMessage(hWnd, WM_OP_FAILED, NULL, NULL);
								if(OBM_LogActive){
									_stprintf_s(OBM_logMsg, _T("Error updating cell (%d,%d) situation."), vx, vy);
									OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 5);
								}
								goto SLEEP;
							}
							else
								cellUpdated = true;

							retSt = UpdateMastSituation(&objtMM);
							if(retSt != RT_NORMAL){
								if(sendMsg)
									SendMessage(hWnd, WM_OP_FAILED, NULL, NULL);
								if(OBM_LogActive){
									_stprintf_s(OBM_logMsg, _T("Error updating mast situation."), vx, vy);
									OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 6);
								}
								goto SLEEP;
							}
							mastUpdated = true;
						}	
					}
					else if(mmClus){
						retCnd = TagRead(&tiMMClusPos, &tagVal);
						if(retCnd != R_NORMAL){
							if(OBM_LogActive){
								_stprintf_s(OBM_logMsg, _T("Error reading cluster position."));
								OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 100);
							}
							goto SLEEP;
						}
						retSt = GetMastPosInfiSC(MAIN_MAST, &px, &py, &zoneIdx);
						if(retSt != RT_NORMAL){
							if(OBM_LogActive){
								_stprintf_s(OBM_logMsg, _T("Error reading mast x,y position."));
								OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 101);
							}
							goto SLEEP;
						}
						retSt = GetZoneIdxPhisCooSC(px, py, &zoneIdx);
						if(retSt != RT_NORMAL){
							if(OBM_LogActive){
								_stprintf_s(OBM_logMsg, _T("Error getting zone idx for pos (%.1f, %1.f)."), px, py);
								OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 102);
							}
							goto SLEEP;
						}
						retSt = GetZoneName(zoneIdx, zoneName);
						if(retSt != RT_NORMAL){
							if(OBM_LogActive){
								_stprintf_s(OBM_logMsg, _T("Error getting zone name"));
								OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 103);
							}
							goto SLEEP;
						}
						retSt = GetZoneSuperZone(zoneName, supZoneName);
						if(retSt != RT_NORMAL){
							if(OBM_LogActive){
								_stprintf_s(OBM_logMsg, _T("Error getting main zone for %s"), zoneName);
								OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 104);
							}
							goto SLEEP;
						}
						clusTD = false;
						if(!_tcscmp(supZoneName, ZONE_REACTOR)){
							OBM_LogFileWrite(OBM_LOG_INF, _T("1"), 2);
							if((tagVal.value.val_float > (float)(clusTDZ3 - clusterMoveTollerance)) && (tagVal.value.val_float < (float)(clusTDZ3 + clusterMoveTollerance)))
								clusTD = true;
						}
						else if(!_tcscmp(supZoneName, ZONE_IO)){
							GetDynCurrentCont(&contIdx);
							if(contIdx == Z1_CONT_TK13){
								if((tagVal.value.val_float > (float)(clusTDZ1_TK13 - clusterMoveTollerance)) && (tagVal.value.val_float < (float)(clusTDZ1_TK13 + clusterMoveTollerance)))
									clusTD = true;
							}else if(contIdx == Z1_CONT_LOAD){
								if((tagVal.value.val_float > (float)(clusTDZ1_LOAD - clusterMoveTollerance)) && (tagVal.value.val_float < (float)(clusTDZ1_LOAD + clusterMoveTollerance)))
									clusTD = true;
							}
						}
						else if(!_tcscmp(supZoneName, ZONE_FFDS)){
							if((tagVal.value.val_float > (float)(clusTDZ23 - clusterMoveTollerance)) && (tagVal.value.val_float < (float)(clusTDZ23 + clusterMoveTollerance)))
								clusTD = true;
						}
						else{
							if((tagVal.value.val_float > (float)(clusTDZ21 - clusterMoveTollerance)) && (tagVal.value.val_float < (float)(clusTDZ21 + clusterMoveTollerance)))
								clusTD = true;
						}

						if(OBM_LogActive){
							_stprintf_s(OBM_logMsg, _T("Cluster gripper movement."));
							OBM_LogFileWrite(OBM_LOG_INF, OBM_logMsg, 2);
						}

						if(!clusTD){
							if(OBM_LogActive){
								_stprintf_s(OBM_logMsg, _T("Cluster gripper is not in touchdown position!"));
								OBM_LogFileWrite(OBM_LOG_WRN, OBM_logMsg, 2);
							}
						}

						if((tagVal.value.val_float > clusStart) && clusTD){

							Sleep(2000);
							retCnd = TagRead(&wTagIdx, &wTagVal);
							if(retCnd != R_NORMAL){
								MessageBox(hWnd, _T("Cannot retrieve 9BP1_STRAIN tag value."), _T("Error"), MB_OK | MB_ICONERROR);
								return(RT_FAILED);
							}

							//Il cluster � sceso//

							if(OBM_LogActive){
								_stprintf_s(OBM_logMsg, _T("Weight: %f, Treshold: %f, Start Pos: %f, Position: %f"),wTagVal.value.val_float,tresholdWeight,clusStart,tagVal.value.val_float);
								OBM_LogFileWrite(OBM_LOG_INF, OBM_logMsg,2);
							}

							if((objtMM.obj[OBJT_N_CLUS] != 0) && (objtMM.obj[OBJT_N_CLUS_CAS] != 0) && (wTagVal.value.val_float <= tresholdWeight)){
								retSt = InsertObject(&objtCell, &objtMM, objtMM.o_id[OBJT_N_CLUS], objtMM.obj[OBJT_N_CLUS], cell.type);
								if(retSt != RT_NORMAL){
									if(OBM_LogActive){
										_stprintf_s(OBM_logMsg, _T("Error inserting cluster in cell."));
										OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 105);
									}
									goto SLEEP;
								}
								retSt = UpdateCellSituation(vx, vy, &objtCell);
								if(retSt != RT_NORMAL){
									if(OBM_LogActive){
										_stprintf_s(OBM_logMsg, _T("Error updating cell (%d,%d) situation."), vx, vy);
										OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 7);
									}
									goto SLEEP;
								}
								cellUpdated = true;
								retSt = UpdateMastSituation(&objtMM);
								if(retSt != RT_NORMAL){
									if(OBM_LogActive){
									_stprintf_s(OBM_logMsg, _T("Error updating mast situation."));
									OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 9);
								}
									goto SLEEP;
								}				
								mastUpdated = true;
							}
							else if((objtCell.obj[OBJT_N_CLUS] != 0) && (objtMM.obj[OBJT_N_CLUS_CAS] != 0) && (wTagVal.value.val_float <= tresholdWeight)){
								retSt = RemoveObject(&objtCell, &objtMM, objtCell.o_id[OBJT_N_CLUS], objtCell.obj[OBJT_N_CLUS]);
								if(retSt != RT_NORMAL){
									if(OBM_LogActive){
										_stprintf_s(OBM_logMsg, _T("Error removing cluster in cell."));
										OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 105);
									}
									goto SLEEP;
								}
								retSt = UpdateCellSituation(vx, vy, &objtCell);
								if(retSt != RT_NORMAL){
									if(OBM_LogActive){
										_stprintf_s(OBM_logMsg, _T("Error updating cell (%d,%d) situation."), vx, vy);
										OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 8);
									}
									goto SLEEP;
								}
								cellUpdated = true;
								retSt = UpdateMastSituation(&objtMM);
								if(retSt != RT_NORMAL){
									if(OBM_LogActive){
										_stprintf_s(OBM_logMsg, _T("Error updating mast situation."));
										OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 10);
									}
									goto SLEEP;
								}				
								mastUpdated = true;
							}
						}
					}
					else if(mmRot){
						retCnd = TagRead(&tiMMAngle, &tagVal);
						if(retCnd != R_NORMAL){
							goto SLEEP;
						}

						mmAngle = tagVal.value.val_float;

						if(OBM_LogActive){
							_stprintf_s(OBM_logMsg, _T("Main mast rotation movement."));
							OBM_LogFileWrite(OBM_LOG_INF, OBM_logMsg, 2);
						}

						if((mmAngle >= (float)(MM_ROT_CL - TOLL_MM_GR)) && (mmAngle <= (float)(MM_ROT_CL + TOLL_MM_GR))){
							//Rotation 45�//

							if(OBM_LogActive){
								_stprintf_s(OBM_logMsg, _T("Main mast angle = 45�."));
								OBM_LogFileWrite(OBM_LOG_INF, OBM_logMsg, 2);
							}

							if((cell.type == CELL_HECA) && (objtMM.obj[OBJT_N_HECA] != 0) && (objtMM.obj[OBJT_N_COVER] != 0)){
								objtCell.obj[OBJT_N_HECA] = objtMM.obj[OBJT_N_HECA];
								objtCell.o_id[OBJT_N_HECA] = objtMM.o_id[OBJT_N_HECA];
								objtMM.obj[OBJT_N_HECA] = 0;
								objtMM.o_id[OBJT_N_HECA] = 0;
								if(objtMM.obj[OBJT_N_FA] != 0){
									objtCell.obj[OBJT_N_FA] = objtMM.obj[OBJT_N_FA];
									objtCell.o_id[OBJT_N_FA] = objtMM.o_id[OBJT_N_FA];
									objtMM.obj[OBJT_N_FA] = 0;
									objtMM.o_id[OBJT_N_FA] = 0;
								}
								
								retSt = UpdateCellSituation(vx, vy, &objtCell);
								if(retSt != RT_NORMAL){
									if(OBM_LogActive){
										_stprintf_s(OBM_logMsg, _T("Error updating cell (%d,%d) situation."), vx, vy);
										OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 11);
									}
									goto SLEEP;
								}
								cellUpdated = true;
								retSt = UpdateMastSituation(&objtMM);
								if(retSt != RT_NORMAL){
									if(OBM_LogActive){
										_stprintf_s(OBM_logMsg, _T("Error updating mast situation."), vx, vy);
										OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 14);
									}
									goto SLEEP;
								}
								mastUpdated = true;
							}

						}
						else if((mmAngle >= (float)(MM_ROT_OP - TOLL_MM_GR)) && (mmAngle <= (float)(MM_ROT_OP + TOLL_MM_GR))){
							//Rotation 0�//
							if(OBM_LogActive){
								_stprintf_s(OBM_logMsg, _T("Main mast angle = 0�."));
								OBM_LogFileWrite(OBM_LOG_INF, OBM_logMsg, 2);
							}
							if((cell.type == CELL_HECA) && (objtCell.obj[OBJT_N_HECA] != 0) && (objtMM.obj[OBJT_N_COVER] != 0)){
								objtMM.obj[OBJT_N_HECA] = objtCell.obj[OBJT_N_HECA];
								objtMM.o_id[OBJT_N_HECA] = objtCell.o_id[OBJT_N_HECA];
								objtCell.obj[OBJT_N_HECA] = 0;
								objtCell.o_id[OBJT_N_HECA] = 0;
								if(objtCell.obj[OBJT_N_FA] != 0){
									objtMM.obj[OBJT_N_FA] = objtCell.obj[OBJT_N_FA];
									objtMM.o_id[OBJT_N_FA] = objtCell.o_id[OBJT_N_FA];
									objtCell.obj[OBJT_N_FA] = 0;
									objtCell.o_id[OBJT_N_FA] = 0;
								}
								
								retSt = UpdateCellSituation(vx, vy, &objtCell);
								if(retSt != RT_NORMAL){
									if(OBM_LogActive){
										_stprintf_s(OBM_logMsg, _T("Error updating cell (%d,%d) situation."), vx, vy);
										OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 12);
									}
									goto SLEEP;
								}
								cellUpdated = true;
								retSt = UpdateMastSituation(&objtMM);
								if(retSt != RT_NORMAL){
									if(OBM_LogActive){
										_stprintf_s(OBM_logMsg, _T("Error updating mast situation."), vx, vy);
										OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 13);
									}
									goto SLEEP;
								}
								mastUpdated = true;
							}
						}
					}
					else if(falvl){
						if((opMode != M_AUTOMATIC) && (opMode != M_SEMIAUTO)){
							retSt = GetMastPosInfiSC(FALC_MAST, &px, &py, &zoneIdx);
							if(retSt != RT_NORMAL){
								goto SLEEP;
							}
							retSt = GetZonePhisVirtCoord(px, py, &vx, &vy);
							if(retSt != RT_NORMAL){
								goto SLEEP;
							}
							retSt = GetCellVirtCoo(vx, vy, &cell);
							if(retSt != RT_NORMAL){
								goto SLEEP;
							}
							falvlData.virtX = vx;
							falvlData.virtY = vy;
							memcpy(&falvlData.cellSituation, &cell.objt_cell, sizeof(OBJTCELL));
							retCnd = TagRead(&tiFALVLLevel, &tagVal);
							if(retCnd != R_NORMAL){
								goto SLEEP;
							}
							falvlData.qouteResult = tagVal.value.val_float;
							GetCamp(&camp);
							falvlData.campSeqNum = camp.seqNum;
							falvlData.campYear = camp.year;
							GetApmsTimeEx(&falvlData.checkTime);
								
							retSt = InsertFALVRecord(falvlData);
							if(retSt != RT_NORMAL){
								goto SLEEP;
							}
						}
					}
				}else if(!ok && nook){
					if(OBM_LogActive){
						_stprintf_s(OBM_logMsg, _T("Movement %d failed."), opCount);
						OBM_LogFileWrite(OBM_LOG_INF, OBM_logMsg, 2);
					}
					if(mmClus && (opMode != M_AUTOMATIC) && (opMode != M_SEMIAUTO)){
						retCnd = TagRead(&tiMMClusPos, &tagVal);
						if(retCnd != R_NORMAL){
							if(OBM_LogActive){
								_stprintf_s(OBM_logMsg, _T("Error reading cluster position."));
								OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 311);
							}
							goto SLEEP;
						}
						
						clgrPos = tagVal.value.val_float;

						retSt = GetMastPosInfiSC(MAIN_MAST, &px, &py, &zoneIdx);
						if(retSt != RT_NORMAL){
							if(OBM_LogActive){
								_stprintf_s(OBM_logMsg, _T("Error reading mast x,y position."));
								OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 101);
							}
							goto SLEEP;
						}
						retSt = GetZoneIdxPhisCooSC(px, py, &zoneIdx);
						if(retSt != RT_NORMAL){
							if(OBM_LogActive){
								_stprintf_s(OBM_logMsg, _T("Error getting zone idx for pos (%.1f, %1.f)."), px, py);
								OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 102);
							}
							goto SLEEP;
						}
						retSt = GetZoneName(zoneIdx, zoneName);
						if(retSt != RT_NORMAL){
							if(OBM_LogActive){
								_stprintf_s(OBM_logMsg, _T("Error getting zone name"));
								OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 103);
							}	
							goto SLEEP;
						}
						retSt = GetZoneSuperZone(zoneName, supZoneName);
						if(retSt != RT_NORMAL){
							if(OBM_LogActive){
								_stprintf_s(OBM_logMsg, _T("Error getting main zone for %s"), zoneName);
								OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 104);
							}
							goto SLEEP;
						}

						if(!_tcscmp(supZoneName, ZONE_REACTOR))
							tdPos = clusTDZ3;
						else if(!_tcscmp(supZoneName, ZONE_IO)){
							GetDynCurrentCont(&contIdx);
							if(contIdx == Z1_CONT_TK13)
								tdPos = clusTDZ1_TK13;
							else if(contIdx == Z1_CONT_LOAD)
								tdPos = clusTDZ1_LOAD;							
						}else if(!_tcscmp(supZoneName, ZONE_FFDS))
							tdPos = clusTDZ23;
						else
							tdPos = clusTDZ21;

						if(clgrPos >= (float)(tdPos - clusterMoveCheck)){
							retCnd = TagRead(&tiMMClusPos, &tagVal);
							if(retCnd != R_NORMAL){
								if(OBM_LogActive){
									_stprintf_s(OBM_logMsg, _T("Error reading cluster position."));
									OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 100);
								}
								goto SLEEP;
							}	
							retSt = GetCellVirtCoo(vx, vy, &cell);
							if(retSt != RT_NORMAL){
								if(OBM_LogActive){
									_stprintf_s(OBM_logMsg, _T("Error getting cell info."));
									OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 42);
								}
								goto SLEEP;
							}
							memcpy(&objtCell, &cell.objt_cell, sizeof(OBJTCELL));
							retSt = GetMastSituation(&objtMM);
							if(retSt != RT_NORMAL){
								if(OBM_LogActive){
									_stprintf_s(OBM_logMsg, _T("Error getting mast situation."));
									OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 43);
								}
								goto SLEEP;
							}
							if((objtMM.obj[OBJT_N_CLUS] == 0) && (objtCell.obj[OBJT_N_CLUS] != 0) && (objtMM.obj[OBJT_N_CLUS_CAS] != 0)){
								retCnd = TagRead(&tiClOverload, &tagVal);
								if(retCnd != R_NORMAL){
									if(OBM_LogActive){
										_stprintf_s(OBM_logMsg, _T("Error reading cluster overload interlock status."));
										OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 312);
									}
									goto SLEEP;
								}
								if(tagVal.value.val_di == 1){
									//Cluster release failed//
									retSt = RemoveObject(&objtCell, &objtMM, objtCell.o_id[OBJT_N_CLUS], objtCell.obj[OBJT_N_CLUS]);
									if(retSt != RT_NORMAL){
										if(OBM_LogActive){
											_stprintf_s(OBM_logMsg, _T("Error removing cluster in cell."));
											OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 313);
										}
										goto SLEEP;
									}
									retSt = UpdateCellSituation(vx, vy, &objtCell);
									if(retSt != RT_NORMAL){
										if(OBM_LogActive){
											_stprintf_s(OBM_logMsg, _T("Error updating cell (%d,%d) situation."), vx, vy);
											OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 314);
										}
										goto SLEEP;
									}
									cellUpdated = true;
									retSt = UpdateMastSituation(&objtMM);
									if(retSt != RT_NORMAL){
										if(OBM_LogActive){
											_stprintf_s(OBM_logMsg, _T("Error updating mast situation."));
											OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 315);
										}
										goto SLEEP;
									}
									mastUpdated = true;
									if(!passive){
										SetObjectOnMast(MAIN_MAST, objtMM);
										retSt = SetWeightOnMast(objtMM);
									}
									retSt = SetMimicMastSituation(MAIN_MAST);
									//SendClgrMsg(clgrInfo.vx, clgrInfo.vy, CLGR_MSG_NO_REL);
									_stprintf_s(opMsg, _T("Cluster release in cell (%d,%d) failed.\nCluster has been inserted back on mast."), vx, vy);							
									::MessageBox(NULL, opMsg, _T("Cluster movement"), MB_OK | MB_ICONWARNING);
								}	
							}else if((objtMM.obj[OBJT_N_CLUS] != 0) && (objtCell.obj[OBJT_N_CLUS] == 0) && (objtMM.obj[OBJT_N_CLUS_CAS] != 0)){
								retCnd = TagRead(&tiClNotEngaged, &tagVal);
								if(retCnd != R_NORMAL){
									if(OBM_LogActive){
										_stprintf_s(OBM_logMsg, _T("Error reading cluster not engaged interlock status."));
										OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 312);
									}
									goto SLEEP;
								}
								if(tagVal.value.val_di == 1){
									//Cluster engage failed//
									retSt = InsertObject(&objtCell, &objtMM, objtMM.o_id[OBJT_N_CLUS], objtMM.obj[OBJT_N_CLUS], cell.type);
									if(retSt != RT_NORMAL){
										if(OBM_LogActive){
											_stprintf_s(OBM_logMsg, _T("Error removing cluster in cell."));
											OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 313);
										}
										goto SLEEP;
									}
									retSt = UpdateCellSituation(vx, vy, &objtCell);
									if(retSt != RT_NORMAL){
										if(OBM_LogActive){
											_stprintf_s(OBM_logMsg, _T("Error updating cell (%d,%d) situation."), vx, vy);
											OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 314);
										}
										goto SLEEP;
									}
									cellUpdated = true;
									retSt = UpdateMastSituation(&objtMM);
									if(retSt != RT_NORMAL){
										if(OBM_LogActive){
											_stprintf_s(OBM_logMsg, _T("Error updating mast situation."));
											OBM_LogFileWrite(OBM_LOG_ERR, OBM_logMsg, 315);
										}
										goto SLEEP;
									}
									mastUpdated = true;
									if(!passive){
										SetObjectOnMast(MAIN_MAST, objtMM);
										retSt = SetWeightOnMast(objtMM);
									}
									retSt = SetMimicMastSituation(MAIN_MAST);
									//SendClgrMsg(clgrInfo.vx, clgrInfo.vy, CLGR_MSG_NO_REL);
									_stprintf_s(opMsg, _T("Cluster engagement from cell (%d,%d) failed.\nCluster has been inserted back in cell."), vx, vy);							
									::MessageBox(NULL, opMsg, _T("Cluster movement"), MB_OK | MB_ICONWARNING);
								}	
							}
						}
					}
				}else{
					if(OBM_LogActive){
						_stprintf_s(OBM_logMsg, _T("Movement %d finished with undefined result."), opCount);
						OBM_LogFileWrite(OBM_LOG_INF, OBM_logMsg, 2);
					}
				}
			}else{
				if(OBM_LogActive){
					_stprintf_s(OBM_logMsg, _T("Movement %d finished."), opCount);
					OBM_LogFileWrite(OBM_LOG_INF, OBM_logMsg, 2);
				}
			}
		}
		
		if(mastUpdated){
			if(manHwnd)
				SendMessage(manHwnd, WM_CHNG_MAST, 0, 0);
			if(!passive){
				SetObjectOnMast(MAIN_MAST, objtMM);
				retSt = SetWeightOnMast(objtMM);
			}
			
			retSt = SetMimicMastSituation(MAIN_MAST);
			//SetToMove(objtMM);
		}

		if(refreshCount == 0){
			refresh = true;
			refreshCount = graphRefreshCycle;
			/*
			if(!passive){
				retSt = SetWeightOnMast(objtMM);
				SetObjectOnMast(MAIN_MAST, objtMM);
			}
			*/
		}else{
			refreshCount--;
			refresh = false;
		}
		
		/*
		if(first)
			retSt = SetMimicMastSituation(MAIN_MAST);
		*/

		if(cellUpdated){
			retSt = SetMimicCellSituationEx(MAIN_MAST, cell.type, zoneIdx, objtCell);
			if(manHwnd)
				SendMessage(manHwnd, WM_CHNG_CELL, vx, vy);
		}
		else{
			if(refresh){
				retSt = GetMastPosInfiSC(MAIN_MAST, &px, &py, &zoneIdx);
				if(retSt != RT_NORMAL)
					goto SLEEP;
				
				retSt = GetZonePhisVirtCoord(px, py, &vx, &vy);
				if(retSt != RT_NORMAL)
					goto SLEEP;
				
				retSt = GetCellVirtCoo(vx, vy, &cell);
				if(retSt != RT_NORMAL)
					goto SLEEP;

				retSt = SetMimicCellSituationEx(MAIN_MAST, cell.type, zoneIdx, cell.objt_cell);

				retSt = SetMimicMastSituation(MAIN_MAST);
			}
		}

		if((opMode != M_AUTOMATIC) && (opMode != M_SEMIAUTO)){
			if(cellUpdated || mastUpdated)
				SetDynSPRefresh(1);
		}
		
SLEEP:	
		if(first)
			first = false;

		Sleep(cycleTime);
	}

	return(RT_NORMAL);
}

/********************************************************************************************/
/*																							*/
/*	Function:		boolTag																	*/
/*																							*/
/*	Description:	Check a tag digital value												*/
/*																							*/
/*	Input:			tagIdx		-	Identifier of the tag to check							*/
/*																							*/
/*	Outout:			tag			-	Digital value of the tag								*/
/*																							*/
/*	Return:			retSt		-	RT_NORMAL	for success									*/
/*								-	RT_FAILED	otherwise									*/
/*																							*/
/********************************************************************************************/
RETSTAT boolTag(TAGIDX tagIdx, bool *tag){
	RETCOND		retCnd;
	TAGVALEX	tagVal;
	
	retCnd = TagRead(&tagIdx, &tagVal);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);
	else{
		if(GtBit((short int)(tagVal.value.val_di), 15) == 1)
			*tag = true;
		else
			*tag = false;
	}
	
	return(RT_NORMAL);
}

/********************************************************************************************/
/*																							*/
/*	Function:		SetToMove																*/
/*																							*/
/*	Description:	Set the _T("TO_MOVE") tags for manual modes									*/
/*																							*/
/*	Input:			hWnd		-	Handle of the calling window							*/
/*																							*/
/*	Return:			retSt		-	RT_NORMAL	for success									*/
/*								-	RT_FAILED	otherwise									*/
/*																							*/
/********************************************************************************************/
RETSTAT SetToMove(OBJTMM objtMM){
	RETSTAT		retSt;
	int			i;
	float		px, py;
	GENIDX		zoneIdx;
	int			vx, vy;
	t_cell		cell;
	bool		onCell;

	onCell = true;
	
	retSt = GetMastPosInfiSC(MAIN_MAST, &px, &py, &zoneIdx);
	if(retSt != RT_NORMAL)
		onCell = false;

	retSt = GetZonePhisVirtCoord(px, py, &vx, &vy);
	if(retSt != RT_NORMAL)
		onCell = false;

	retSt = GetCellVirtCoo(vx, vy, &cell);
	if(retSt != RT_NORMAL)
		onCell = false;

	if(!onCell){
		retSt = VotedTagWrite(TWN_CLUS_MOVE, 0, 0, DIG_VALUE);
		if(retSt != RT_NORMAL)
			return(retSt);
	
		retSt = VotedTagWrite(TWN_FA_MOVE, 0, 0, DIG_VALUE);
		if(retSt != RT_NORMAL)
			return(retSt);

		retSt = VotedTagWrite(TWN_HECA_MOVE, 0, 0, DIG_VALUE);
		if(retSt != RT_NORMAL)
			return(retSt);

		retSt = VotedTagWrite(TWN_HECA_PLUG_MOVE, 0, 0, DIG_VALUE);
		if(retSt != RT_NORMAL)
			return(retSt);

		retSt = VotedTagWrite(TWN_CLUSFRM_MOVE, 0, 0, DIG_VALUE);
		if(retSt != RT_NORMAL)
			return(retSt);

		retSt = VotedTagWrite(TWN_CLUSCAS_MOVE, 0, 0, DIG_VALUE);
		if(retSt != RT_NORMAL)
			return(retSt);

		retSt = VotedTagWrite(TWN_FFDS_PLUG_MOVE, 0, 0, DIG_VALUE);
		if(retSt != RT_NORMAL)
			return(retSt);

		return(RT_NORMAL);
	}

	if((objtMM.obj[OBJT_N_CLUS_CAS] != 0) && ((objtMM.obj[OBJT_N_CLUS] != 0) || (cell.objt_cell.obj[OBJT_N_CLUS] != 0))){
		retSt = VotedTagWrite(TWN_CLUSCAS_MOVE, 1, 0, DIG_VALUE);
		if(retSt != RT_NORMAL)
			return(retSt);
		
		retSt = VotedTagWrite(TWN_CLUS_MOVE, 1, 0, DIG_VALUE);
		if(retSt != RT_NORMAL)
			return(retSt);

		return(RT_NORMAL);
	}
	else{
		retSt = VotedTagWrite(TWN_CLUS_MOVE, 0, 0, DIG_VALUE);
		if(retSt != RT_NORMAL)
			return(retSt);
		for(i = 0; i < N_MAX_NONAM_OBJ; i++){
			if(i != OBJT_N_CLUS){
				switch(i){
				case OBJT_N_FA:
					if(cell.type == CELL_FA){
						if((objtMM.obj[OBJT_N_FA] != 0) || (cell.objt_cell.obj[OBJT_N_FA] != 0)){
							retSt = VotedTagWrite(TWN_FA_MOVE, 1, 0, DIG_VALUE);
							if(retSt != RT_NORMAL)
								return(retSt);
						}
						else{
							retSt = VotedTagWrite(TWN_FA_MOVE, 0, 0, DIG_VALUE);
							if(retSt != RT_NORMAL)
								return(retSt);
						}
					}
					else if(cell.type == CELL_HECA){
						if((cell.objt_cell.obj[OBJT_N_HECA] != 0) && (objtMM.obj[OBJT_N_COVER] == 0) && (cell.objt_cell.obj[OBJT_N_COVER] == 0) && ((objtMM.obj[OBJT_N_FA] != 0) || (cell.objt_cell.obj[OBJT_N_FA] != 0))){
							retSt = VotedTagWrite(TWN_FA_MOVE, 1, 0, DIG_VALUE);
							if(retSt != RT_NORMAL)
								return(retSt);
						}
						else{
							retSt = VotedTagWrite(TWN_FA_MOVE, 0, 0, DIG_VALUE);
							if(retSt != RT_NORMAL)
								return(retSt);
						}
					}
					else if(cell.type == CELL_FFDS_CASK){
						if((cell.objt_cell.obj[OBJT_N_FFDS_COV] == 0) && (objtMM.obj[OBJT_N_FFDS_COV] == 0) && ((objtMM.obj[OBJT_N_FA] != 0) || (cell.objt_cell.obj[OBJT_N_FA] != 0))){
							retSt = VotedTagWrite(TWN_FA_MOVE, 1, 0, DIG_VALUE);
							if(retSt != RT_NORMAL)
								return(retSt);
						}
						else{
							retSt = VotedTagWrite(TWN_FA_MOVE, 0, 0, DIG_VALUE);
							if(retSt != RT_NORMAL)
								return(retSt);
						}
					}
					else{
						retSt = VotedTagWrite(TWN_FA_MOVE, 0, 0, DIG_VALUE);
						if(retSt != RT_NORMAL)
							return(retSt);
					}
					break;
				case OBJT_N_HECA:
					if((objtMM.obj[OBJT_N_HECA] != 0) || ((cell.objt_cell.obj[OBJT_N_HECA] != 0) && (cell.objt_cell.obj[OBJT_N_COVER] != 0))){
						retSt = VotedTagWrite(TWN_HECA_MOVE, 1, 0, DIG_VALUE);
						if(retSt != RT_NORMAL)
							return(retSt);
					}
					else{
						retSt = VotedTagWrite(TWN_HECA_MOVE, 0, 0, DIG_VALUE);
						if(retSt != RT_NORMAL)
							return(retSt);
					}
					break;
				case OBJT_N_COVER:
					if((objtMM.obj[OBJT_N_COVER] != 0) || (cell.objt_cell.obj[OBJT_N_COVER] != 0)){
						retSt = VotedTagWrite(TWN_HECA_PLUG_MOVE, 1, 0, DIG_VALUE);
						if(retSt != RT_NORMAL)
							return(retSt);
					}
					else{
						retSt = VotedTagWrite(TWN_HECA_PLUG_MOVE, 0, 0, DIG_VALUE);
						if(retSt != RT_NORMAL)
							return(retSt);
					}
					break;
				case OBJT_N_CLUS_FRM:
					if((objtMM.obj[OBJT_N_CLUS_FRM] != 0) || (cell.objt_cell.obj[OBJT_N_CLUS_FRM] != 0)){
						retSt = VotedTagWrite(TWN_CLUSFRM_MOVE, 1, 0, DIG_VALUE);
						if(retSt != RT_NORMAL)
							return(retSt);
					}
					else{
						retSt = VotedTagWrite(TWN_CLUSFRM_MOVE, 0, 0, DIG_VALUE);
						if(retSt != RT_NORMAL)
							return(retSt);
					}
					break;
				case OBJT_N_CLUS_CAS:
					if(((objtMM.obj[OBJT_N_CLUS_CAS] != 0) || (cell.objt_cell.obj[OBJT_N_CLUS_CAS] != 0)) && (cell.objt_cell.obj[OBJT_N_COVER] == 0) && (cell.objt_cell.obj[OBJT_N_FFDS_COV] == 0)){
						retSt = VotedTagWrite(TWN_CLUSCAS_MOVE, 1, 0, DIG_VALUE);
						if(retSt != RT_NORMAL)
							return(retSt);
					}
					else{
						retSt = VotedTagWrite(TWN_CLUSCAS_MOVE, 0, 0, DIG_VALUE);
						if(retSt != RT_NORMAL)
							return(retSt);
					}
					break;
				case OBJT_N_FFDS_COV:
					if((objtMM.obj[OBJT_N_FFDS_COV] != 0) || (cell.objt_cell.obj[OBJT_N_FFDS_COV] != 0)){
						retSt = VotedTagWrite(TWN_FFDS_PLUG_MOVE, 1, 0, DIG_VALUE);
						if(retSt != RT_NORMAL)
							return(retSt);
					}
					else{
						retSt = VotedTagWrite(TWN_FFDS_PLUG_MOVE, 0, 0, DIG_VALUE);
						if(retSt != RT_NORMAL)
							return(retSt);
					}
					break;
				}
			}
		}
	}
	return(RT_NORMAL);
}

/********************************************************************************************/
/*																							*/
/*	Function:		SetWeightOnMast															*/
/*																							*/
/*	Description:	Set the _T("MM_EXP") tag for manual modes									*/
/*																							*/
/*	Input:			objtMM		-	Mast situation											*/
/*																							*/
/*	Return:			retSt		-	RT_NORMAL	for success									*/
/*								-	RT_FAILED	otherwise									*/
/*																							*/
/********************************************************************************************/
RETSTAT SetWeightOnMast(OBJTMM objtMM){
	RETSTAT			retSt;
	float			clgrWeight;
	float			objWeight;
	float			weight;
	int				j;
	
	clgrWeight = 0.0;
	if((objtMM.obj[OBJT_N_CLUS] != 0) && (objtMM.obj[OBJT_N_CLUS_CAS] != 0)){
		retSt = GetObjWeight(objtMM.o_id[OBJT_N_CLUS], &objWeight);
		if(retSt != RT_NORMAL)
			return (RT_INVOBJ);
		clgrWeight = objWeight;
	}

	weight = 0.0;
	objWeight = 0.0;
	for(j = 0; j < N_MAX_NONAM_OBJ; j++){
		if(objtMM.obj[j] != 0){
			if(j < N_MAX_NAMED_OBJ){
				if(((j == OBJT_N_CLUS) && (objtMM.obj[OBJT_N_CLUS_CAS] == 0)) || (j != OBJT_N_CLUS)){
					retSt = GetObjWeight(objtMM.o_id[j], &objWeight);
					if(retSt != RT_NORMAL)
						return (RT_INVOBJ);
				}
			}
			else{
				retSt = GetObjtWeight(objtMM.obj[j], &objWeight);
				if(retSt != RT_NORMAL)
					return (RT_INVOBJT);
			}
			weight = weight + objWeight;
		}
	}

	retSt = VotedTagWriteEx(TWN_MM_EXP_WEIGHT, 0, weight, FLT_VALUE);
	if(retSt != RT_NORMAL)
		return(RT_FAILED);
						
	retSt = VotedTagWriteEx(TWN_MM_CL_EXP_WEIGHT, 0, clgrWeight, FLT_VALUE);
	if(retSt != RT_NORMAL)
		return(RT_FAILED);
	
	return(RT_NORMAL);
}

/*********************************************************************************************
**********************************************************************************************
**
** Function:		OBM_LogFileWrite
**
** Description:		Print a message in the application log file,
**
** Input:			cmd				- _T("ERR") - error, _T("WRN") - warning, _T("OK ") - success.
**					Comment			- Message description.
**
** Return:			int				- 1 for success.
**									- -1 otherwise.
** 
**********************************************************************************************
*********************************************************************************************/
int OBM_LogFileWrite(int cmd, TCHAR *Comment, int errNum){
	FILE		*LogFile;
	SYSTEMTIME	timeStamp;
	TCHAR		timeStr[100];
	
	if(OBM_LogActive){

		errno_t err;
		err = _tfopen_s(&LogFile,OBM_logPath, _T("a"));
		if (err != 0)
			return -1;

		//LogFile = _tfopen(OBM_logPath, _T("a"));
		//if(LogFile == NULL)
		//	return -1;
		
		GetLocalTime(&timeStamp);
		_stprintf_s(timeStr, _T("[%02d:%02d.%02d.%03d] [%02d-%02d-%4d]"), timeStamp.wHour, timeStamp.wMinute, timeStamp.wSecond, timeStamp.wMilliseconds, timeStamp.wDay, timeStamp.wMonth, timeStamp.wYear);
		if(cmd == OBM_LOG_ERR)
			_ftprintf(LogFile,_T("%s  - ERR -  %s Err.N� %d.\n"), timeStr, Comment, errNum);
		else if(cmd == OBM_LOG_INF)
			_ftprintf(LogFile,_T("%s  - INF -  %s\n"), timeStr, Comment);
		else if(cmd == OBM_LOG_WRN)
			_ftprintf(LogFile,_T("%s  - WRN -  %s\n"), timeStr, Comment);
		else
			_ftprintf(LogFile,_T("%s  - UNK -  %s\n"), timeStr, Comment);

		if(fclose(LogFile)!=0)
			return -1;
	}
	
	return 0;
}

RETSTAT StopMovement(void){
	return VotedTagWrite(TWN_START_MOV, 0, 0, DIG_VALUE);
}

void clgrMsg(LPVOID param){
	CLGR_MSG	*local;
	TCHAR		opMsg[512];

	local = (CLGR_MSG *)(param);

	if(local->msgType == CLGR_MSG_NO_ENG)
		_stprintf_s(opMsg, _T("Cluster engagement from cell (%d,%d) failed.\nCluster has been inserted back on mast."), local->vx, local->vy);
	else if(local->msgType == CLGR_MSG_NO_REL)
		_stprintf_s(opMsg, _T("Cluster release in cell (%d,%d) failed.\nCluster has been inserted back in cell."), local->vx, local->vy);
									
	::MessageBox(NULL, opMsg, _T("Cluster movement"), MB_OK | MB_ICONWARNING);
}

void SendClgrMsg(int vx, int vy, int type){
	CLGR_MSG	param;
	UINT		msgThread;

	param.vx = vx;
	param.vy = vy;
	param.msgType = type;

	msgThread = _beginthread(clgrMsg, 0, (LPVOID)(&param));

}